"""
GConf Export - Utility to export XML, behaves like 
'gconftool-2 --dump /gconf/path > xml' 
Copyright (c) 2006 Peter Moberg <moberg.peter@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

On Debian systems, the complete text of the GNU General Public
License can be found in /usr/share/common-licenses/GPL file.
"""

import gconf
import types

class GConfExport:
	""" Allow us to export from gconf to XML """
	def __init__(self, client):
		self.client = client
		self.indentStep = "  "

	"""  Returns the get function for a value """
	def printEntry(self, key, value, indent):
		
		""" If there is an unset value, return empty string """
		if (value == None):
			return ""

		try:
			if (value.type == gconf.VALUE_INVALID):
				raise "Invalid value in gconf"
				return ""

			elif (value.type == gconf.VALUE_STRING):
				return self.__getDataValXml("string", self.client.get_string(key), indent)

			elif (value.type == gconf.VALUE_INT):
				return self.__getDataValXml("int", str(self.client.get_int( key )), indent)

			elif (value.type == gconf.VALUE_FLOAT):
				return self.__getDataValXml("float", str(self.client.get_float(key)), indent)

			elif (value.type == gconf.VALUE_BOOL):
				return self.__getDataValXml("bool", str(self.client.get_bool(key)), indent)

			elif (value.type == gconf.VALUE_LIST):
				return self.__getListValXml( value, key, indent ) 

			elif (value.type == gconf.VALUE_SCHEMA):
				raise "Can not export schema, not implemented"
			elif (value.type == gconf.VALUE_PAIR):
				raise "Can not export pair, not implemented"
			else:
				return ""
		except Exception, e:
			#print ""
			print "ERROR in printEntry: "
			print key
			print e
			#print ""
			return ""

	def __getDataValXml(self, type, data, indent):
		""" Converts a data value to XML """
		space = self.__indentSpace(indent)
		space2 = self.__indentSpace(indent+1)
		if (type == "bool"):
			data = data.lower()
		elif (type == "string"):
			data = data.replace('<', '&lt;').replace('>','&gt;')
			
		return ( space + "<value>\n" + space2 + "<" + type + ">" + data + "</" + type + ">\n" +space + "</value>\n")

	def __getListValXml(self, value, key, indent):
		""" Converts a list of values into XML """
		xml = ""
		strType = ""
		listType = value.get_list_type()
		list = []
	
		if (listType == gconf.VALUE_STRING):
			strType = "string"
			list = self.client.get_list(key, gconf.VALUE_STRING)
		elif (listType == gconf.VALUE_INT):
			strType = "int"
			list = self.client.get_list(key, gconf.VALUE_INT)
		elif (listType == gconf.VALUE_FLOAT):
			strType = "float"
			list = self.client.get_list(key, gconf.VALUE_FLOAT)
		elif (listType == gconf.VALUE_BOOL):
			strType = "bool"
			list = self.client.get_list(key, gconf.VALUE_BOOL)

		xml += self.__indentSpace(indent) + "<list type=\"" + strType + "\">\n"
		try:
			for item in list:
				if type(item) == types.StringType:
					output = item.replace('<', '&lt;').replace('>','&gt;')
				else:
					output = str(item)
				xml += self.__indentSpace(indent+1) + "<value>\n" + self.__indentSpace(indent+2) +"<" + strType + ">" + output + "</" + strType + ">\n" + self.__indentSpace(indent+1) + "</value>\n"

			xml += self.__indentSpace(indent) + "</list>\n"
		except Exception, e:
			print "__getListValXml:"
			print e
		return xml
				

	def __parseTree(self, path, indent):
		xml = ""
		entries = self.client.all_entries(path)

		for entry in entries:
			key = entry.get_key()
			#print "key: " + key
			try:
				value = entry.get_value()
				xml += self.__indentSpace(indent) + "<entry>\n"
				xml += self.__indentSpace(indent+1) + "<key>" + key + "</key>\n"
				xml += self.printEntry( key, entry.get_value(), indent+2 )
				xml += self.__indentSpace(indent) + "</entry>\n"
			except Exception, e:
				print "__parseTree:"
				print e

		dirs = self.client.all_dirs(path)
		for dir in dirs:
			xml += self.__parseTree(dir, indent)

		return xml


	def exportDir(self, path, indent):
		""" Recursively exports a GConf dir to XML """
		xml = self.__indentSpace(indent) + "<entrylist base=\"" + path + "\">\n"
		xml += self.__parseTree(path, indent+1)		
		xml += self.__indentSpace(indent) + "</entrylist>\n"

		return xml

	def exportKey(self, key, indent):
		""" Exports a single key to XML """
		xml = self.__indentSpace(indent) + "<entrylist base=\"" + key[0:key.rfind('/')] + "\">\n"
		xml += self.__indentSpace(indent+1) + "<entry>\n"
		xml += self.__indentSpace(indent+2) + "<key>" + key + "</key>\n"

		value = self.client.get(key)
		xml += self.printEntry(key, value, indent+3)		

		xml += self.__indentSpace(indent+1) + "</entry>\n"
		xml += self.__indentSpace(indent) + "</entrylist>\n"
		return xml
	
	def export(self, dirs, singleKeys):
		""" Exports all dirs in 'dirs' and keys in 'singleKeys' to XML. This XML is compatible with gconftool-2 """
		xml = "<gconfentryfile>\n"

			
		for key in singleKeys:
			xml += self.exportKey(key, 2)
			
		for dir in dirs:
			xml += self.exportDir(dir, 2)

		xml += "</gconfentryfile>\n"
		return xml

	def __indentSpace(self, depth):
		""" Return correct indentation width """
		space = ""
		for i in range(depth):
			space += self.indentStep
		return space


